package com.songlanyun.modules.shop.service.impl;

import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.songlanyun.common.enums.LockPrefixConstant;
import com.songlanyun.common.enums.MemberConstant;
import com.songlanyun.common.enums.SysConstant;
import com.songlanyun.common.exception.RRException;
import com.songlanyun.common.utils.*;
import com.songlanyun.common.utils.custom.MathUtils;
import com.songlanyun.common.validator.ValidatorUtils;
import com.songlanyun.common.validator.group.AddGroup;
import com.songlanyun.modules.account.entity.AccountEntity;
import com.songlanyun.modules.account.entity.UserIdentityAssetEntity;
import com.songlanyun.modules.account.entity.UserInfoEntity;
import com.songlanyun.modules.account.entity.UserShopRoleEntity;
import com.songlanyun.modules.account.model.vo.AccountVO;
import com.songlanyun.modules.account.service.AccountService;
import com.songlanyun.modules.account.service.UserIdentityAssetService;
import com.songlanyun.modules.account.service.UserInfoService;
import com.songlanyun.modules.account.service.UserShopRoleService;
import com.songlanyun.modules.exception.MemberException;
import com.songlanyun.modules.exception.ShopException;
import com.songlanyun.modules.shop.dao.ShopDao;
import com.songlanyun.modules.shop.entity.ShopAdminRelationEntity;
import com.songlanyun.modules.shop.entity.ShopApplyEntity;
import com.songlanyun.modules.shop.entity.ShopEntity;
import com.songlanyun.modules.shop.entity.ShopUpdateRecordEntity;
import com.songlanyun.modules.shop.model.dto.ShopApplyDTO;
import com.songlanyun.modules.shop.model.dto.ShopRateDTO;
import com.songlanyun.modules.shop.model.vo.ShopInfoVO;
import com.songlanyun.modules.shop.model.vo.ShopVO;
import com.songlanyun.modules.shop.model.vo.ShopWithdrawVO;
import com.songlanyun.modules.shop.service.*;
import com.songlanyun.modules.user.entity.SysUserEntity;
import com.songlanyun.modules.user.entity.SysUserEntityDTO;
import com.songlanyun.modules.user.exception.UserException;
import com.songlanyun.modules.user.service.SysRoleService;
import com.songlanyun.modules.user.service.SysUserRoleService;
import com.songlanyun.modules.user.service.SysUserService;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.util.concurrent.TimeUnit;


@Service("yxtShopService")
public class ShopServiceImpl extends ServiceImpl<ShopDao, ShopEntity> implements ShopService {

    @Resource
    private SysUserService sysUserService;

    @Resource
    private SysUserRoleService sysUserRoleService;

    @Resource
    private AccountService accountService;

    @Resource
    private ShopAdminRelationService shopAdminRelationService;

    @Resource
    private ShopUserRoleConfigService shopUserRoleConfigService;

    @Resource
    private UserShopRoleService userShopRoleService;

    @Resource
    private UserInfoService userInfoService;

    @Resource
    private UserIdentityAssetService userIdentityAssetService;

    @Resource
    private SysRoleService sysRoleService;

    @Resource
    private ShopApplyService shopApplyService;

    @Resource
    private UnionBusinessClassifyService unionBusinessClassifyService;

    @Autowired
    private RedissonClient redissonClient;

    @Value("${shop.mobile}")
    private String mobile;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {

        IPage<ShopInfoVO> page = this.baseMapper.shopPage(new Query<ShopInfoVO>().getPage(params), params);

        page.getRecords().forEach(shop -> {
            //查询商家是否分配管理员账号
            shop.setDistribution(this.baseMapper.verifyAdminPriByShopId(shop.getId()));
            if (shop.getUnionBusiness()) {
                //设置联盟商家分类
                shop.setUnionBusinessClassifyList(unionBusinessClassifyService.queryListByShopId(shop.getId()));
            }
        });

        return new PageUtils(page);
    }


    @Override
    public ShopEntity selectPlatformShop() {
        return baseMapper.selectPlatformShop();
    }

    @Override
    public Long selectPlatformShopId(boolean tw) {
        ShopEntity shopEntity = this.selectPlatformShop();
        if (ObjectUtil.isNull(shopEntity)) {
            if (tw) {
                throw new RRException(ShopException.PT_SHOP_NOT_EXIST);
            } else {
                return null;
            }
        }
        return shopEntity.getId();

    }

    @Override
    public void updateShop(ShopEntity shopEntity) {
        ShopEntity shop = this.getById(shopEntity.getId(), true);
        BeanUtil.copyPropertiesIgnoreNull(shopEntity, shop);
        this.updateById(shop);
    }

    /**
     * 平台初始化店铺
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void initializeShop(ShopApplyDTO dto) {
        //第一次创建时，需初始化管理员信息
        if (dto.getUser() == null) {
            throw new RRException(UserException.USER_INFO_NOT_EXIST);
        }
        //检验用户名和手机号
        sysUserService.verifyUserName(dto.getUser().getUsername(), dto.getUser().getMobile());

        //初始化平台会员  --不能登录
        AccountEntity account = new AccountEntity(mobile, 0L, ",");
        account.setRegisterTime(new Date());
        account.setSubjectionShopId(0L);
        accountService.save(account);

        //平台会员信息
        UserInfoEntity userInfoEntity = new UserInfoEntity();
        userInfoEntity.setId(account.getId());
        userInfoEntity.adminInit();
        userInfoService.save(userInfoEntity);

        //平台资产信息
        UserIdentityAssetEntity userIdentityAssetEntity = new UserIdentityAssetEntity();
        userIdentityAssetEntity.setId(account.getId());
        userIdentityAssetService.save(userIdentityAssetEntity);

        //初始化商家申请记录  -- 保存商家企业信息
        shopApplyService.initApply(dto, account.getId());

        //初始化平台店铺   -- 保存商家店铺信息
//        ShopEntity shop = shopApplyService.saveShopByApply(dto);//将审核记录的数据填充到商家中
        ShopEntity shop = cn.hutool.core.bean.BeanUtil.toBean(dto, ShopEntity.class);
        shop.setUserId(account.getId());//会员id
        shop.setPlatformShop(true);//是否是平台商家 0：不是 1：是
        this.save(shop);

        //更新平台会员的 隶属的商家店铺
        account.setSubjectionShopId(shop.getId());//隶属的商家店铺
        accountService.updateById(account);

        //初始化平台商家等级设置
        shopUserRoleConfigService.saveShopConfig(shop.getId(), false);

        //保存用户信息
        SysUserEntity user = savePTShopUser(dto);

        //绑定账号
        //保存商家与管理帐户的关系
        ShopAdminRelationEntity shopAdmin = new ShopAdminRelationEntity(shop.getId(), user.getUserId());
        shopAdmin.setPrimared(true);//是否是店铺的主帐号
        shopAdminRelationService.save(shopAdmin);

        //初始化平台会员的等级
        userShopRoleService.init(account.getId(), shop.getId(), MemberConstant.MemberLevel.CITY_AGENT.getCode(), new BigDecimal(0));
    }


    @Override
    public ShopEntity loadShopBy(Long shopId, Boolean tw) {

        ShopEntity shop = this.getById(shopId);
        if (shop == null) {
            if (tw) {
                throw new RRException(ShopException.SHOP_NOT_EXIST);
            }
        }
        return shop;
    }

    /**
     * 平台为商家分配管理员账号
     *
     * @param shop
     */
    @Override
    @Transactional
    public void assignedAccount(ShopEntity shop, SysUserEntityDTO userDTO) {

        //保存加盟商家管理员角色账号
        SysUserEntity user = new SysUserEntity();
        BeanUtils.copyProperties(userDTO, user);//将记录拷贝一份保存
        user.setIsShop(true);//商家管理员
        sysRoleService.saveUserRole(user, SysConstant.JM_SHOP_ADMIN_ROLE);

        //保存商家与管理帐户的关系      //商家id//管理员id//主账号
        ShopAdminRelationEntity shopAdmin = new ShopAdminRelationEntity(shop.getId(), user.getUserId(), true);
        shopAdminRelationService.save(shopAdmin);

    }

    @Override
    public ShopEntity getShopByUserId(Long userId, boolean unionBusiness) {
        return this.lambdaQuery()
                .eq(ShopEntity::getUserId, userId)
                .eq(ShopEntity::getLockStatus, 0)
                .eq(ShopEntity::getUnionBusiness, unionBusiness)
                .last("limit 1")
                .one();
    }

    @Override
    public Long getShopIdByUserId(Long userId, boolean unionBusiness) {
        ShopEntity shop = this.lambdaQuery()
                .eq(ShopEntity::getUserId, userId)
                .eq(ShopEntity::getLockStatus, 0)
                .eq(ShopEntity::getUnionBusiness, unionBusiness)
                .last("limit 1")
                .one();
        if (ObjectUtil.isNotNull(shop)) {
            return shop.getId();
        }
        return null;
    }

    @Override
    public ShopEntity getSubShopById(Long userId, boolean unionBusiness) {
        return baseMapper.getSubShopById(userId, unionBusiness);
    }

    @Override
    @Transactional
    public void saveShopAdmin(SysUserEntity user, Long shopId, boolean isShop) {
        sysUserService.saveUser(user);//保存用户
        user.setIsShop(isShop);//设置是否是商家管理员
        if (isShop) {//如果是商家创建子管理员的话，需要创建账号与商家的关系表

            ShopAdminRelationEntity shopAdminRelationEntity = new ShopAdminRelationEntity();
            shopAdminRelationEntity.setShopId(shopId);
            shopAdminRelationEntity.setAdminId(user.getUserId());
            shopAdminRelationEntity.setPrimared(false);//非主账号
            shopAdminRelationService.save(shopAdminRelationEntity);
        }
    }


    @Override
    public Long getUserIdByAdminId(Long userId, boolean unionBusiness) {
        return baseMapper.getUserIdByAdminId(userId, unionBusiness);
    }

    /**
     * 删除商家
     *
     * @param shopIds
     */
    @Override
    @Transactional
    public void deleteShop(List<Long> shopIds) {
        //删除商家后，需要删除对应的关系
        this.removeByIds(shopIds);

        //删除商家管理员及所有关联子管理员
        for (Long shopId : shopIds) {
            List<ShopAdminRelationEntity> list = shopAdminRelationService.list(
                    new LambdaQueryWrapper<ShopAdminRelationEntity>()
                            .eq(ShopAdminRelationEntity::getShopId, shopId)
            );

            list.forEach(v -> {
                //删除商家管理员账号
                sysUserService.removeById(v.getAdminId());
                //删除商家与管理员的关系
                shopAdminRelationService.removeById(v.getId());
            });

        }

    }

    @Override
    public List<ShopEntity> nearbyShop(Map<String, Object> params) {
        String lon = MapUtil.getStr(params, "lon");//经度
        String lat = MapUtil.getStr(params, "lat");//纬度
        String shopId = MapUtil.getStr(params, "shop_id");//店铺id
        String shopName = MapUtil.getStr(params, "shop_name");//店铺名称
        Boolean unionBusiness = MapUtil.getBool(params, "union_business");//是否是联盟商家
        if (StringUtils.isBlank(lon) || StringUtils.isBlank(lat)) {
            throw new RRException(ShopException.LON_AND_LAT_NOT_EXIST);
        }

        //查询所有商铺
        List<ShopEntity> list = this.list(
                new LambdaQueryWrapper<ShopEntity>()
                        .eq(ShopEntity::getLockStatus, 0)
                        .eq(ShopEntity::getIsShow, true)
                        .like(StringUtils.isNotBlank(shopName), ShopEntity::getShopName, shopName)
                        .eq(ShopEntity::getUnionBusiness, ObjectUtil.isNull(unionBusiness) ? 0 : unionBusiness)//是否是联盟商家
                        .ne(shopId != null, ShopEntity::getId, shopId)//排除当前店铺，方便后面将当前店铺排到首位
        );

        list.forEach(v -> {
            //计算经纬度距离并设置
            mathCalculate(lon, lat, v);
        });

        //根据list中对象的时间排序
        list.sort(new Comparator<ShopEntity>() {
            @Override
            public int compare(ShopEntity o1, ShopEntity o2) {
                //升序
                return o1.getDistance().compareTo(o2.getDistance());
            }
        });

        //将当前店铺排到首位
        if (shopId != null) {
            ShopEntity shopEntity = this.baseMapper.selectById(shopId);
            //计算经纬度距离并设置
            mathCalculate(lon, lat, shopEntity);
            list.add(0, shopEntity);
        }


        return list;
    }

    @Override
    public ShopEntity getById(Long shopId, boolean isThrow) {
        ShopEntity shopEntity = this.baseMapper.selectById(shopId);
        if (shopEntity == null) {
            if (isThrow) {
                throw new RRException(ShopException.SHOP_NOT_EXIST);
            }
        }
        return shopEntity;
    }

    @Override
    public ShopEntity loadByIdForLock(Long shopId, boolean isThrow) {
        ShopEntity shopEntity = this.baseMapper.loadByIdForLock(shopId);
        if (shopEntity == null) {
            if (isThrow) {
                throw new RRException(ShopException.SHOP_NOT_EXIST);
            }
        }
        return shopEntity;
    }

    /**
     * 获取商家当前可提现
     */
    @Override
    public BigDecimal getGainsAble(Long shopId) {
        ShopEntity shopEntity = this.getById(shopId, false);
        if (shopEntity == null) {
            return BigDecimal.ZERO;
        }
        return shopEntity.getGainsAble();//可提现

    }

    /**
     * 商家所得提现
     *
     * @param shopId
     * @param money
     * @return
     */
    @Override
    public ShopEntity updateShopGains(Long shopId, BigDecimal money) {
        ShopEntity shopEntity = null;
        RLock lock = redissonClient.getLock(LockPrefixConstant.SHOP_GAINS + shopId);
        lock.lock(2, TimeUnit.SECONDS);
        try {
            shopEntity = this.getById(shopId, true);
            //判断金额是否充足
            if (shopEntity.getGainsAble().compareTo(money) < 0) {//商家可提现所得是否到达上限
                throw new RRException(ShopException.SHOP_WITHDRAW_INSUFFICIENT_FUND);
            }
            //更新商家可提现所得、已提现所得
            shopEntity.decGains(money);
            this.baseMapper.updateById(shopEntity);
        } finally {
            lock.unlock();
        }
        return shopEntity;
    }

    @Override
    public void resetShopPassword(Long shopId) {
        //根据商家id查询管理员账号
        SysUserEntity user = sysUserService.selectShopAdmin(shopId, true);
        user.passwordEn("123456");

        sysUserService.updateById(user);
    }

    @Override
    public void updateAverageById(Long shopId, BigDecimal average) {
        this.update(
                new LambdaUpdateWrapper<ShopEntity>()
                        .eq(ShopEntity::getId, shopId)
                        .set(ShopEntity::getAverage, average)
        );
    }

    @Override
    public ShopWithdrawVO getWithdrawAmount(Long shopId) {
        return this.baseMapper.getWithdrawAmount(shopId);
    }

    @Override
    public SysUserEntity getAdminByShopId(Long shopId) {
        return sysUserService.selectShopAdmin(shopId, false);
    }

    /**
     * @param dto
     * @param shop 已保存的商家信息
     */
    @Override
    @Transactional
    public void updateByShopAllInfo(ShopApplyDTO dto, ShopEntity shop) {
        //修改商家企业信息 -- 在商家申请记录中修改
        ShopApplyEntity apply = shopApplyService.getApplyByUserId(shop.getUserId(), shop.getUnionBusiness());
        dto.setId(null);
        if (apply == null) {
            //初始化商家申请记录  -- 保存商家企业信息
            apply = shopApplyService.initApply(dto, shop.getUserId());
        } else {
            BeanUtil.copyPropertiesIgnoreNull(dto, apply);
            shopApplyService.updateById(apply);
        }

        //修改商家店铺信息
        ShopEntity shopEntity = shopApplyService.saveShopByApply(dto);
        BeanUtil.copyPropertiesIgnoreNull(shopEntity, shop);
        shop.setPlatformShop(true);
        this.baseMapper.updateById(shop);

        //修改管理员信息
        if (dto.getUser() != null) {
            SysUserEntity sysUser = this.getAdminByShopId(shop.getId());
            if (sysUser != null) {
                //检验用户名和手机号
                if (!sysUser.getUsername().equals(dto.getUser().getUsername())) {
                    sysUserService.verifyUserName(dto.getUser().getUsername());
                }

                BeanUtil.copyPropertiesIgnoreNull(dto.getUser(), sysUser);
                //防止重置密码
                if (StringUtils.isBlank(dto.getUser().getPassword())) {
                    sysUser.setPassword(null);
                } else {
                    sysUser.setPassword(new Sha256Hash(dto.getUser().getPassword(), sysUser.getSalt()).toHex());
                }
                sysUser.setIsShop(true);//设置是商家管理员
                sysUserService.updateById(sysUser);
            } else {
                savePTShopUser(dto);

            }

        }
    }


    @Override
    public ShopInfoVO getShopInfo(Long shopId) {
        //查询企业信息和店铺信息
        ShopInfoVO vo = this.baseMapper.getShopInfo(shopId);
        //是否已分配管理员账号
        //查询平台管理员有没有初始化过自己的店铺
        vo.setDistribution(this.baseMapper.verifyAdminPriByShopId(shopId));

        return vo;
    }

    @Override
    public ShopEntity getShopByAdminId(Long adminId, boolean unionBusiness) {
        return this.baseMapper.getShopByAdminId(adminId, unionBusiness);
    }

    @Override
    public Long getAdminPriByShopId(Long id) {
        return this.baseMapper.getAdminPriByShopId(id);
    }

    @Override
    public String getCodeByShopId(Long shopId) {
        if (shopId == 0) {
            //平台管理员获取平台商家会员的邀请码
            shopId = this.selectPlatformShopId(false);
            if (ObjectUtil.isNull(shopId)) {
                return null;
            }
        }
        return this.baseMapper.getCodeByShopId(shopId);
    }

    @Override
    public Boolean isShopByAccountId(Long userId, boolean unionBusiness) {
        Long shopId = this.baseMapper.getShopIdByUserId(userId, unionBusiness);
        return shopId != null;
    }

    @Override
    public List<ShopEntity> allShopCity(String city, boolean unionBusiness) {
        return this.baseMapper.selectList(
                new LambdaQueryWrapper<ShopEntity>()
                        .eq(ShopEntity::getLockStatus, 0)
                        .eq(ShopEntity::getIsShow, true)
                        .eq(ShopEntity::getUnionBusiness, unionBusiness)
                        .and(p -> p.eq(ShopEntity::getProvinceName, city)
                                .or(c -> c.eq(ShopEntity::getCityName, city)))
                        .orderByAsc(ShopEntity::getCreateTime)
        );
    }

    @Override
    public List<ShopEntity> allShop(boolean unionBusiness) {
        return this.baseMapper.selectList(
                new LambdaQueryWrapper<ShopEntity>()
                        .eq(ShopEntity::getLockStatus, 0)
                        .eq(ShopEntity::getIsShow, true)
                        .eq(ShopEntity::getUnionBusiness, unionBusiness)
                        .orderByAsc(ShopEntity::getCreateTime)
        );
    }

    @Override
    public void setCommissionRate(ShopRateDTO dto) {
        ValidatorUtils.validateEntity(dto);
        ShopEntity shopEntity = this.loadShopBy(dto.getShopId(), true);
        shopEntity.setCommissionRate(dto.getCommissionRate());
        this.baseMapper.updateById(shopEntity);
    }

    @Override
    public Integer getShopNum(String areaCode, boolean unionBusiness) {
        return this.baseMapper.selectCount(new LambdaQueryWrapper<ShopEntity>()
                .eq(ShopEntity::getAreaCode, areaCode)
                .eq(ShopEntity::getUnionBusiness, unionBusiness));
    }

    @Override
    public void show(Long shopId) {
        ShopEntity shop = this.getById(shopId, true);
        shop.setIsShow(!shop.getIsShow());
        this.baseMapper.updateById(shop);
    }

    @Override
    public ShopEntity getApiShopInfo(Long accountId, boolean unionBusiness) {
        return this.lambdaQuery()
                .eq(ShopEntity::getUserId, accountId)
                .eq(ShopEntity::getLockStatus, 0)
                .eq(ShopEntity::getUnionBusiness, unionBusiness)
                .last("limit 1")
                .one();
    }

    /**
     * 保存平台商家管理员用户
     *
     * @param dto
     * @return
     */
    private SysUserEntity savePTShopUser(ShopApplyDTO dto) {
        SysUserEntityDTO dtoUser = dto.getUser();
        ValidatorUtils.validateEntity(dtoUser, AddGroup.class);//校验
        //检验用户名和手机号
        sysUserService.verifyUserName(dtoUser.getUsername(), dto.getMobile());
        SysUserEntity user = new SysUserEntity();
        BeanUtil.copyPropertiesIgnoreNull(dtoUser, user);
        user.setIsShop(true);//设置是商家管理员
        //保存平台商家管理员角色账号
        sysRoleService.saveUserRole(user, SysConstant.PT_SHOP_ADMIN_ROLE);
        return user;
    }

    /**
     * 计算经纬度距离 并设置商家中
     */
    @Override
    public void mathCalculate(String lon, String lat, ShopEntity shop) {
        //计算经纬度距离
        double calculate = MapTools.calculate(lon, lat, shop.getTxLongitude(), shop.getTxLatitude());
        //不保留小数
        BigDecimal bg = new BigDecimal(calculate);
        double calculateNew = bg.setScale(1, BigDecimal.ROUND_HALF_UP).doubleValue();
        shop.setDistance(calculateNew);
    }

}
